home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / PC.C < prev    next >
C/C++ Source or Header  |  1997-07-30  |  29KB  |  1,307 lines

  1. /* OS- and machine-dependent stuff for IBM-PC running MS-DOS
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  * Mods by KO4KS
  4.  */
  5. #ifdef MSDOS
  6. #include "global.h"
  7. #include <conio.h>
  8. #include "commands.h"
  9. #include <sys/stat.h>
  10. #include <go32.h>
  11. #include <process.h>
  12. #include <fcntl.h>
  13. #include <stdarg.h>
  14. #include <bios.h>
  15. #include <dpmi.h>
  16. #include <signal.h>
  17. #include "mbuf.h"
  18. #include "proc.h"
  19. #include "iface.h"
  20. #include "session.h"
  21. #include "tty.h"
  22. #include "smtp.h"
  23.  
  24. #if !defined(_lint)
  25. static char rcsid[] OPTIONAL = "$Id: pc.c,v 1.25 1997/07/31 00:44:20 root Exp root $";
  26. #endif
  27.  
  28. #define FP_OFF( fp )( (unsigned )( fp ))
  29. static unsigned Nfiles = 128;
  30.  
  31.  
  32. extern void displayStatLine (int offset, int phase, int onlymarquee);
  33. extern void setscreens (int back, int fore, int clr);
  34. static int _go32_dpmi_unchain_protected_mode_interrupt_vector (uint irq, _go32_dpmi_seginfo * info);
  35. static void eoi (void);
  36. void DOSinit (void);
  37. void DOSterm (void);
  38. static void irq0 (void);
  39. static int16 clockbits (void);
  40. static void ctick (void);
  41. static long bioscnt (void);
  42.  
  43. extern struct proc *Display;
  44. extern char vgaDesired;
  45. extern void volatile *lastkernelevent;
  46. volatile int Tick;
  47. volatile int32 Clock;
  48.  
  49. static unsigned char orgMode;
  50.  
  51. #define MAXSCR 20
  52. typedef struct screenstorage {
  53.     char *scrptr;
  54. } screenstorage;
  55.  
  56. static screenstorage DOSscreens[MAXSCR];
  57. static size_t scrsize;
  58.  
  59.  
  60. static int saved_break;
  61.  
  62. struct int_tab {
  63.     __dpmi_paddr old;    /* Previous handler at this vector */
  64.     _go32_dpmi_seginfo new;    /* Current handler, with wrapper info */
  65.     void (*func) (int);    /* Function to call on interrupt */
  66.     int arg;        /* Arg to pass to interrupt function */
  67.     int chain;        /* Is interrupt chained to old handler? */
  68. } Int_tab [16];
  69.  
  70.  
  71. static const char fkeysyntax1[] =
  72.     "key   num    key    num    key    num    key    num   key    num\n"
  73.     "f1     59    sf1     84    cf1     94    af1    104   pgup    73\n"
  74.     "f2     60    sf2     85    cf2     95    af2    105   pgdn    81\n";
  75. static const char fkeysyntax2[] =
  76.     "f3     61    sf3     86    cf3     96    af3    106   home    71\n"
  77.     "f4     62    sf4     87    cf4     97    af4    107   end     79\n"
  78.     "f5     63    sf5     88    cf5     98    af5    108   arup    72\n";
  79. static const char fkeysyntax3[] =
  80.     "f6     64    sf6     89    cf6     99    af6    109   ardn    80\n"
  81.     "f7     65    sf7     90    cf7    100    af7    110   ar l    75\n"
  82.     "f8     66    sf8     91    cf8    101    af8    111   ar r    77\n";
  83. static const char fkeysyntax4[] =
  84.     "f9     67    sf9     92    cf9    102    af9    112   ins     82\n"
  85.     "f10    68    sf10    93    cf10   103    af10   113   del     83\n"
  86.     "f11   133    sf11   135    cf11   137    af11   139   stab    15\n";
  87. static const char fkeysyntax5[] =
  88.     "f12   134    sf12   136    cf12   138    af12   140   cprtsc 114\n"
  89.     "cpgup 132    cpgdn  118    chome  119    cend   117\n"
  90.     "usage: fkey <key number> [<value> | \"string\"]\n";
  91.  
  92. static const char fkeyoor[] = "fkey number out of range.\n";
  93. static const char fkeynf[] = "fkey number not found\n";
  94. static const char fkeynoval[] = "fkey %d has no assigned value.\n";
  95. static const char noprompt[] = "\b\b\b\b\b\b\b\b        \b\b\b\b\b\b\b\b";
  96. static const char somemore[] = "--More--";
  97.  
  98. static FILE *Rawterm;
  99. static char Ttbuf[BUFSIZ];
  100.  
  101.  
  102.  
  103. /* Called at startup time to set up misc I/O related functions */
  104. void
  105. ioinit (int hinit)
  106. {
  107. union REGS inregs;
  108. extern int _fmode;
  109.  
  110.     _fmode = O_BINARY;
  111.     /* Get some memory on the heap so interrupt calls to malloc
  112.      * won't fail unnecessarily
  113.      */
  114.     free (malloc ((uint) hinit));
  115.  
  116.     Rawterm = fopen ("con", "wb");
  117.     setbuf (Rawterm, Ttbuf);
  118.  
  119.     /* Increase the size of the file table.
  120.      * Note: this causes MS-DOS
  121.      * to allocate a block of memory to hold the larger file table.
  122.      * By default, this happens right after our program, which means
  123.      * any further sbrk() calls from morecore (called from malloc)
  124.      * will fail. Hence there is now code in alloc.c that can call
  125.      * the MS-DOS allocmem() function to grab additional MS-DOS
  126.      * memory blocks that are not contiguous with the program and
  127.      * put them on the heap.
  128.      */
  129.     inregs.h.ah = 0x67;
  130.     inregs.x.bx = Nfiles;    /* Up to the base of the socket numbers */
  131.     (void) intdos (&inregs, &inregs);
  132.  
  133.     saved_break = getcbrk ();
  134.     (void) setcbrk (0);
  135.     (void) signal (SIGINT, SIG_IGN);
  136.  
  137.     /* Chain protected mode keyboard interrupt */
  138.     LOCK_FUNCTION(kbint);
  139.     LOCK_FUNCTION(ksignal);
  140.     LOCK_FUNCTION(istate);
  141.     LOCK_VARIABLE(Ksig);
  142.     LOCK_VARIABLE(lastkernelevent);
  143.     (void) setvect (1, 1, (void (*)(int)) kbint, 0);
  144.  
  145.     /* Chain timer interrupt */
  146.     LOCK_FUNCTION(ctick);
  147.     LOCK_VARIABLE(Tick);
  148.     LOCK_VARIABLE(Clock);
  149.     (void) setvect (0, 1, (void (*)(int)) ctick, 0);
  150.  
  151.     LOCK_ARRAY(Int_tab);
  152.     LOCK_FUNCTION(eoi);
  153.     LOCK_FUNCTION(irq0);
  154. }
  155.  
  156.  
  157.  
  158. /* Called just before exiting to restore console state */
  159. void
  160. iostop (void)
  161. {
  162. struct iface *ifp, *iftmp;
  163. void (**fp) (void);
  164.  
  165.     setbuf (Rawterm, NULLCHAR);
  166.     (void) setcbrk (saved_break);
  167.  
  168.     for (ifp = Ifaces; ifp != NULL; ifp = iftmp) {
  169.         iftmp = ifp->next;
  170.         (void) if_detach (ifp);
  171.     }
  172.     /* Call list of shutdown functions */
  173.     for (fp = Shutdown; *fp != NULL; fp++)
  174.         (**fp) ();
  175.  
  176.     /* Restore previous timer and keyboard interrupts */
  177.     (void) freevect (0);
  178.     (void) freevect (1);
  179. }
  180.  
  181.  
  182.  
  183. #ifdef SHELL
  184. /* Spawn subshell */
  185. int
  186. doshell (int argc, char *argv[], void *p)
  187. {
  188. char *command;
  189. int ret;
  190.  
  191.     if (argc == 1 || !stricmp (argv[1], "/c")) {
  192.         if ((command = getenv ("COMSPEC")) == NULLCHAR)
  193.             command = "COMMAND.COM";
  194.         ret = spawnvp (P_WAIT, command, argv);
  195.     } else
  196.         ret = spawnvp (P_WAIT, argv[1], (argv + 1));
  197.  
  198.     return ret;
  199. }
  200. #endif
  201.  
  202.  
  203.  
  204. #ifdef ALLCMD
  205. /* Spawn mailer as subshell */
  206. int
  207. dobmail (int argc, char *argv[], void *p)
  208. {
  209. char *command;
  210. int ret;
  211.  
  212.     if ((command = getenv ("MAILER")) == NULLCHAR)
  213.         command = "BM.EXE";
  214.     ret = spawnvp (P_WAIT, command, argv);
  215.  
  216.     smtptick (NULL);    /* tickle smtp to send any mail */
  217.     return ret;
  218. }
  219. #endif /*ALLCMD*/
  220.  
  221.  
  222.  
  223. static int
  224. kbchar (void)
  225. {
  226. int c;
  227.  
  228.     while ((c = kbraw ()) == 0)
  229.         kwait (kbint);
  230.     return (c);
  231. }
  232.  
  233.  
  234.  
  235. /* Flush the raw terminal output */
  236. void
  237. rflush (void)
  238. {
  239.     (void) fflush (Rawterm);
  240. }
  241.  
  242.  
  243.  
  244. #ifdef ALLCMD
  245. struct funcstr {
  246.     unsigned char fkey;
  247.     char alloced;
  248.     char *fvalue;
  249. };
  250.  
  251. static struct funcstr fkeys[] =
  252. {
  253.     15, 0, NULLCHAR,    /* tab + shift */
  254.     59, 1, NULLCHAR,    /* F1 */
  255.     60, 1, NULLCHAR,    /* F2 */
  256.     61, 1, NULLCHAR,    /* F3 */
  257.     62, 1, NULLCHAR,    /* F4 */
  258.     63, 0, NULLCHAR,    /* F5 */
  259.     64, 0, NULLCHAR,    /* F6 */
  260.     65, 0, NULLCHAR,    /* F7 */
  261.     66, 0, NULLCHAR,    /* F8 */
  262.     67, 0, NULLCHAR,    /* F9 */
  263.     68, 0, NULLCHAR,    /* F10 */
  264.     71, 1, NULLCHAR,    /* home*/
  265.     72, 1, "\033[A",    /* up arrow*/
  266.     73, 1, NULLCHAR,    /* pgup */
  267.     75, 1, "\033[D",    /* left arrow */
  268.     77, 1, "\033[C",    /* right arrow */
  269.     79, 1, NULLCHAR,    /* end */
  270.     80, 1, "\033[B",    /* down arrow */
  271.     81, 1, NULLCHAR,    /* pgdn */
  272.     82, 1, NULLCHAR,    /* ins */
  273.     83, 1, NULLCHAR,    /* del */
  274.     84, 0, NULLCHAR,    /* F1 + shift*/
  275.     85, 0, NULLCHAR,    /* F2 + shift*/
  276.     86, 0, NULLCHAR,    /* F3 + shift*/
  277.     87, 0, NULLCHAR,    /* F4 + shift*/
  278.     88, 0, NULLCHAR,    /* F5 + shift*/
  279.     89, 0, NULLCHAR,    /* F6 + shift*/
  280.     90, 0, NULLCHAR,    /* F7 + shift*/
  281.     91, 0, NULLCHAR,    /* F8 + shift*/
  282.     92, 0, NULLCHAR,    /* F9 + shift*/
  283.     93, 0, NULLCHAR,    /* F10 + shift*/
  284.     94, 0, NULLCHAR,    /* F1 + control*/
  285.     95, 0, NULLCHAR,    /* F2 + control*/
  286.     96, 0, NULLCHAR,    /* F3 + control*/
  287.     97, 0, NULLCHAR,    /* F4 + control*/
  288.     98, 0, NULLCHAR,    /* F5 + control*/
  289.     99, 0, NULLCHAR,    /* F6 + control*/
  290.     100, 0, NULLCHAR,    /* F7 + control*/
  291.     101, 0, NULLCHAR,    /* F8 + control*/
  292.     102, 0, NULLCHAR,    /* F9 + control*/
  293.     103, 0, NULLCHAR,    /* F10 + control*/
  294.     104, 0, NULLCHAR,    /* F1 + alt*/
  295.     105, 0, NULLCHAR,    /* F2 + alt*/
  296.     106, 0, NULLCHAR,    /* F3 + alt*/
  297.     107, 0, NULLCHAR,    /* F4 + alt*/
  298.     108, 0, NULLCHAR,    /* F5 + alt*/
  299.     109, 0, NULLCHAR,    /* F6 + alt*/
  300.     110, 0, NULLCHAR,    /* F7 + alt*/
  301.     111, 0, NULLCHAR,    /* F8 + alt*/
  302.     112, 0, NULLCHAR,    /* F9 + alt*/
  303.     113, 0, NULLCHAR,    /* F10 + alt*/
  304.     114, 0, NULLCHAR,    /* PrtSc + ctl*/
  305.     117, 0, NULLCHAR,    /* end  + ctl */
  306.     118, 0, NULLCHAR,    /* pgup + ctl */
  307.     119, 0, NULLCHAR,    /* home + ctl */
  308.     132, 0, NULLCHAR,    /* pgdn + ctl */
  309.     133, 0, NULLCHAR,    /* F11 */
  310.     134, 0, NULLCHAR,    /* F12 */
  311.     135, 0, NULLCHAR,    /* F11 + shift */
  312.     136, 0, NULLCHAR,    /* F12 + shift */
  313.     137, 0, NULLCHAR,    /* F11 + control */
  314.     138, 0, NULLCHAR,    /* F11 + control */
  315.     139, 0, NULLCHAR,    /* F11 + alt */
  316.     140, 0, NULLCHAR,    /* F11 + alt */
  317.     0, 0, NULLCHAR
  318. };
  319.  
  320. static char Leftover = 0;
  321. static char *Nextkey = NULLCHAR;
  322.  
  323. #endif /*ALLCMD*/
  324.  
  325.  
  326.  
  327. /* Read characters from the keyboard, translating them to "real" ASCII.
  328.  * If none are ready, block. The F-10 key is special; translate it to -2.
  329.  */
  330. #ifdef ALLCMD
  331. int
  332. kbread (void)
  333. {
  334. int c, i, j;
  335.  
  336.     if ((c = Leftover) != 0) {
  337.         Leftover = *Nextkey++;
  338.         return c;
  339.     }
  340.  
  341.     c = kbchar ();
  342.     if ((c & 0xff) == 0) {
  343.         /* Lead-in to a special char */
  344.         c = (c >> 8) & 0xff;    /*lint !e702 */
  345.         switch (c) {
  346.             case 3:        /* NULL (bizzare!) */
  347.                 c = 0;
  348.                 break;
  349.             case 72:    /* UP ARROW key (used as previous history command) */
  350.                 if (Current == Command) {
  351.                     c = UPARROW;
  352.                     break;
  353.                 }
  354.                 goto all;
  355.             case 80:    /* DOWN ARROW key (used as next history command) */
  356.                 if (Current == Command) {
  357.                     c = DNARROW;
  358.                     break;
  359.                 }
  360.                 goto all;
  361.             case 68:    /* F-10 key (used as command-mode escape) */
  362.                 if (fkeys[10].fvalue == NULLCHAR) {
  363.                     c = -2;
  364.                     break;
  365.                 }
  366.                 goto all;
  367.             case 82:    /* INSERT key (used as status line toggle) */
  368.                 if (fkeys[19].fvalue == NULLCHAR) {
  369.                     c = -105;
  370.                     break;
  371.                 }
  372.                 goto all;
  373.             case 83:    /* DELETE key (used as flow mode toggle) */
  374.                 if (fkeys[20].fvalue == NULLCHAR) {
  375.                     c = -106;
  376.                     break;
  377.                 }
  378.                 goto all;
  379.             case 71:    /* HOME key (used to kick this session) */
  380.                 if (fkeys[11].fvalue == NULLCHAR) {
  381.                     c = -107;
  382.                     break;
  383.                 }
  384.                 goto all;
  385.             case 79:    /* END key (used to kill this session) */
  386.                 if (fkeys[16].fvalue == NULLCHAR) {
  387.                     c = -108;
  388.                     break;
  389.                 }
  390.                 goto all;
  391.             case 73:    /* PGUP key (used to toggle to previous session) */
  392.                 if (fkeys[13].fvalue == NULLCHAR) {
  393.                     c = -109;
  394.                     break;
  395.                 }
  396.                 goto all;
  397.             case 81:    /* PGDN key (used to toggle to next session) */
  398.                 if (fkeys[18].fvalue == NULLCHAR) {
  399.                     c = -110;
  400.                     break;
  401.                 }
  402.                 goto all;
  403.             default:    /* Dunno what it is */
  404. all:
  405.                 if (c > 58 && c < 68) {    /* F1 to F9 */
  406.                     if (fkeys[c - 58].fvalue == NULLCHAR) {
  407.                         c = (c - 56) * -1;    /* NO fkey defined - WG7J */
  408.                         break;
  409.                     }
  410.                 }
  411.                 for (i = 0; (j = fkeys[i].fkey) != 0; i++)
  412.                     if (j == c) {
  413.                         Nextkey = fkeys[i].fvalue;
  414.                         if (Nextkey == NULLCHAR) {
  415.                             c = -1;
  416.                             return c;
  417.                         }
  418.                         /* If first char of fvalue is '~'
  419.                          * switch to command session.
  420.                          */
  421.                         if ((c = *Nextkey++) == '~') {
  422.                             c = -2;
  423.                             Leftover = *Nextkey++;
  424.                         } else {
  425.                             if (c != 0)
  426.                                 Leftover = *Nextkey++;
  427.                             else
  428.                                 c = -1;
  429.                         }
  430.                         return c;
  431.                     }
  432.                 c = -1;
  433.         }
  434.     } else
  435.         c = c & 0xff;
  436.     return c;
  437. }
  438.  
  439. int
  440. dofkey (int argc, char *argv[], void *p)
  441. {
  442. int c, i, j;
  443. char *q, *r;
  444. char str[100];
  445.  
  446.     if (argc == 1) {
  447.         tputs (fkeysyntax1);
  448.         tputs (fkeysyntax2);
  449.         tputs (fkeysyntax3);
  450.         tputs (fkeysyntax4);
  451.         tputs (fkeysyntax5);
  452.         return 0;
  453.     }
  454.     c = atoi (argv[1]);
  455.     if (c == 0 || c > 255) {
  456.         tputs (fkeyoor);
  457.         return 1;
  458.     }
  459.     for (j = 0; (i = fkeys[j].fkey) != 0; j++)
  460.         if (i == c)
  461.             break;
  462.  
  463.     if (i == 0) {
  464.         tputs (fkeynf);
  465.         return 1;
  466.     }
  467.     if (argc == 2) {
  468.         q = fkeys[j].fvalue;
  469.         r = str;
  470.         if (q == NULLCHAR)
  471.             tprintf (fkeynoval, c);
  472.         else {
  473.             while (*q)
  474.                 if (*q < ' ') {    /* This is ASCII dependent !! */
  475.                     *r++ = '^';
  476.                     *r++ = *q++ + 0x40;
  477.                 } else
  478.                     *r++ = *q++;
  479.             *r = '\0';
  480.             tprintf ("fkey = %s\n", str);
  481.         }
  482.         return 0;
  483.     }
  484.     if (argc == 3) {
  485.         if (fkeys[j].alloced)
  486.             fkeys[j].alloced = 0;
  487.         else if (fkeys[j].fvalue != NULLCHAR)
  488.             free (fkeys[j].fvalue);
  489.  
  490.         r = str;
  491.         q = argv[2];
  492.         while (*q) {
  493.             if (*q == '^') {    /* ^ gives control char next */
  494.                 q++;
  495.                 if (*q == '^') {
  496.                     *r++ = *q++;    /* No, he wants a ^ */
  497.                 } else {
  498.                     *r++ = *q++ & 0x1f;
  499.                 }
  500.             } else
  501.                 *r++ = *q++;
  502.         }
  503.         *r = '\0';
  504.         fkeys[j].fvalue = strdup (str);
  505.     }
  506.     return 0;
  507. }
  508.  
  509. #else /*ALLCMD*/
  510.  
  511. int
  512. kbread (void)
  513. {
  514. int c;
  515.  
  516.     if ((c = kbchar ()) == 0) {
  517.         /* Lead-in to a special char */
  518.         c = kbchar ();
  519.         if (Current == Command) {    /* Check for command recall */
  520.             if (c == 72)    /* UP arrow */
  521.                 return UPARROW;
  522.             if (c == 80)    /* DOWN arrow */
  523.                 return DNARROW;
  524.         }
  525.         switch (c) {
  526.             case 3:/* NULL (bizzare!) */
  527.                 c = 0;
  528.                 break;
  529.             case 68:    /* F-10 key (used as command-mode escape) */
  530.                 c = -2;
  531.                 break;
  532.             case 83:    /* DEL key */
  533.                 c = 0x7f;
  534.                 break;
  535.             default:    /* Dunno what it is */
  536.                 if (c > 58 && c < 68)    /* F1 to F9 */
  537.                     c = (c - 56) * -1;
  538.                 else
  539.                     c = -1;
  540.         }
  541.     }
  542.     return c;
  543. }
  544. #endif /*ALLCMD*/
  545.  
  546.  
  547.  
  548. /* Disable hardware interrupt */
  549. int
  550. maskoff (uint irq)
  551. {
  552.     if (irq < 8)
  553.         setbit (0x21, (char) (1 << irq));
  554.     else if (irq < 16) {
  555.         irq -= 8;
  556.         setbit (0xa1, (char) (1 << irq));
  557.     } else
  558.         return -1;
  559.  
  560.     return 0;
  561. }
  562.  
  563.  
  564.  
  565. /* Enable hardware interrupt */
  566. int
  567. maskon (uint irq)
  568. {
  569.     if (irq < 8)
  570.         clrbit (0x21, 1 << irq);
  571.     else if (irq < 16) {
  572.         irq -= 8;
  573.         clrbit (0xa1, 1 << irq);
  574.     } else
  575.         return -1;
  576.  
  577.     return 0;
  578. }
  579.  
  580.  
  581.  
  582. /* Return 1 if specified interrupt is enabled, 0 if not, -1 if invalid */
  583. int
  584. getmask (unsigned irq)
  585. {
  586.     if (irq < 8)
  587.         return (inportb (0x21) & (1 << irq)) ? 0 : 1;
  588.     else if (irq < 16) {
  589.         irq -= 8;
  590.         return (inportb (0xa1) & (1 << irq)) ? 0 : 1;
  591.     } else
  592.         return -1;
  593. }
  594.  
  595.  
  596.  
  597. /* Called from assembler stub linked to BIOS interrupt 1C, called on each
  598.  * hardware clock tick. Signal a clock tick to the timer process.
  599.  */
  600. static void
  601. ctick (void)
  602. {
  603.     Tick++;
  604.     Clock++;        /* Keep system time */
  605.     ksignal ((void *) &Tick, 1);
  606. }
  607.  
  608. END_OF_FUNCTION(ctick)
  609.  
  610.  
  611.  
  612. /* Called from the timer process on every tick. NOTE! This function
  613.  * can NOT be called at interrupt time because it calls the BIOS
  614.  */
  615. void
  616. pctick (void)
  617. {
  618. long t;
  619. static long oldt = 0;    /* Value of bioscnt() on last call */
  620.  
  621.     /* Check for day change */
  622.     t = bioscnt ();
  623.     if (t < oldt)     /* Call the regular DOS time func to handle the midnight flag */
  624.         (void) time (NULL);
  625.  
  626. }
  627.  
  628.  
  629.  
  630. /* Set bit(s) in I/O port */
  631. void
  632. setbit (uint port, uint8 bits)
  633. {
  634.     outportb ((int16) port, inportb ((int16) port) | bits);
  635. }
  636.  
  637.  
  638.  
  639. /* Clear bit(s) in I/O port */
  640. void
  641. clrbit (uint port, uint8 bits)
  642. {
  643.     outportb ((int16) port, inportb ((int16) port) & ~bits);
  644. }
  645.  
  646.  
  647.  
  648. /* Set or clear selected bits(s) in I/O port */
  649. void
  650. writebit (uint port, uint8 mask, int val)
  651. {
  652. uint8 x;
  653.  
  654.     x = inportb ((int16) port);
  655.     if (val)
  656.         x |= mask;
  657.     else
  658.         x &= ~mask;
  659.     outportb ((int16) port, x);
  660. }
  661.  
  662.  
  663.  
  664. static void stowit (size_t index, int save, unsigned char attr);
  665. extern unsigned char SCREENwidth, SCREENlength;
  666. extern int STATLINE;
  667. extern struct session *ScreenOwner;    /* Session currently displayed */
  668.  
  669.  
  670.  
  671. void
  672. newscreen (struct session *sp)
  673. {
  674.     if (sp != NULLSESSION) {
  675.         sp->screen = callocw (1, sizeof (struct screen));
  676.         sp->screen->statline = uchar(STATLINE);
  677.     }
  678. }
  679.  
  680.  
  681.  
  682. void
  683. freescreen (struct session *sp)
  684. {
  685.     if (sp == NULLSESSION || sp->screen == NULLSCREEN)
  686.         return;
  687.     if ((sp->screen->save != NULLCHAR) && sp->screen->save != (char *) 1)
  688.         free (sp->screen->save);
  689.     free ((char *) sp->screen);
  690. }
  691.  
  692.  
  693.  
  694. /* Save specified session screen and resume console screen */
  695. void
  696. swapscreen (struct session *old, struct session *new)
  697. {
  698. struct text_info tr;
  699. unsigned char attr;
  700.  
  701.     if (old == new)
  702.         return;        /* Nothing to do */
  703.  
  704.     (void) fflush (Rawterm);
  705.     gettextinfo (&tr);
  706.     if (old != NULLSESSION) {
  707.         /* Save old screen */
  708.         if (old->screen->save == NULLCHAR)
  709.             old->screen->save = (char *) 1;
  710.         old->screen->row = wherey ();
  711.         old->screen->col = wherex ();
  712.         old->screen->attr = tr.attribute;
  713.  
  714.         if (old->screen->save != NULLCHAR) {
  715.             if (old->split) {
  716.                 window (1, 1, SCREENwidth, SCREENlength);
  717.                 tr.winbottom = SCREENlength;
  718.             }
  719.             stowit ((unsigned long) old->index, 1, 0);
  720.             /* save it */
  721.         }
  722.     }
  723.     if (new != NULLSESSION) {
  724.         /* Load new screen */
  725.         if (new->screen->save != NULLCHAR) {
  726.             if (new->split)
  727.                 window (1, 1, SCREENwidth, SCREENlength - 2);
  728.             else
  729.                 window (1, 1, SCREENwidth, SCREENlength);
  730.  
  731.             setscreens ((new->screen->attr >> 4) & 0x07, new->screen->attr & 0x0f, 0);
  732.             stowit ((unsigned long) new->index, 0, new->screen->attr);
  733.             /* retrieve it */
  734.                 new->screen->attr &= 0x7f;
  735.             /* remove color change bit */
  736.  
  737.                 /* if (STATLINE && (Current == Command)) */
  738.                 window (1, 1 + new->screen->statline, SCREENwidth, SCREENlength - (new->split * 2));
  739.             gotoxy (new->screen->col, new->screen->row);
  740.             textattr (new->screen->attr);
  741.             new->screen->save = NULLCHAR;
  742.         } else {
  743.             window (1, 1, SCREENwidth, SCREENlength);
  744.             clrscr ();    /* Start with a fresh slate */
  745.             if (new->split) {
  746.                 new->tsavex = 1;
  747.                 new->tsavey = 1;
  748.                 new->bsavex = 1;
  749.                 new->bsavey = SCREENlength - 1;
  750.                 window (1, SCREENlength - 1, SCREENwidth, SCREENlength);
  751.                 gettextinfo (&tr);
  752.                 attr = ((tr.attribute & 0x0f) << 4) + ((tr.attribute & 0x70) >> 4);
  753.                 textattr (attr);
  754.                 clrscr ();
  755.                 cputs ("_\b");
  756.                 window (1, 1 + new->screen->statline, SCREENwidth, SCREENlength - 2 - new->screen->statline);
  757.                 textattr (tr.attribute);
  758.             } else
  759.                 window (1, 1 + new->screen->statline, SCREENwidth, SCREENlength - new->screen->statline);
  760.         }
  761.     }
  762.     ScreenOwner = new;
  763.     displayStatLine (0, 1, 0);
  764.     alert (Display, 1);    /* Wake him up */
  765. }
  766.  
  767.  
  768.  
  769. void
  770. display (int i, void *v1, void *v2)
  771. {
  772. int c;
  773. struct session *sp;
  774. int statsize;
  775.  
  776.     server_disconnect_io ();
  777.     /* This is very tricky code. Because the value of "Current" can
  778.      * change any time we do a kwait, we have to be careful to detect
  779.      * any change and go back and start again.
  780.      */
  781.     for ( ; ; ) {
  782.         sp = Current;
  783.  
  784.         if (sp->morewait) {
  785.             kwait (&sp->row);
  786.             if (sp != Current || sp->row <= 0) {
  787.                 /* Current changed value, or the user
  788.                  * hasn't really hit a key
  789.                  */
  790.                 continue;
  791.             }
  792.             /* Erase the prompt */
  793.             cprintf (noprompt);
  794.             rflush ();
  795.         }
  796.         sp->morewait = 0;
  797.         if ((c = rrecvchar (sp->output)) == EOF) {
  798.             /* the alert() in swapscreen will cause this to
  799.              * return EOF when current changes
  800.              */
  801.             kwait (NULL);    /* Prevent a nasty loop */
  802.             continue;
  803.         }
  804. #ifdef SCREENSAVER
  805.         sskick ();
  806. #endif
  807.         if (sp->split) {
  808.             if (c == 0x0a) {
  809.                 cputs (Eol);
  810.                 clreol ();
  811.             } else
  812.                 putch (c);
  813.         } else
  814.             cprintf ("%c", c);
  815.  
  816.         /* Fix by Ron Murray, vk6zjm */
  817.         if (sp->record != NULLFILE)    /* Don't save CR if ascii mode */
  818.             if (c != '\r' || sockmode (sp->output, -1) != SOCK_ASCII)
  819.                 putc (c, sp->record);
  820.  
  821.         statsize = 0;
  822.         if (sp->screen->statline)
  823.             statsize = ((sp == Command) ? getStatlines() : 1);
  824.  
  825.         if (sp->flowmode && c == '\n' && sp->row > 0 && --sp->row == statsize) {
  826.             cprintf (somemore);
  827.             sp->morewait = 1;
  828.             sp->row = 0;
  829.         }
  830.     }
  831. }
  832.  
  833.  
  834.  
  835. /* Return time since startup in milliseconds. Resolution is improved
  836.  * below 55 ms (the clock tick interval) by reading back the instantaneous
  837.  * 8254 counter value and combining it with the global clock tick counter.
  838.  *
  839.  * Reading the 8254 is a bit tricky since a tick could occur asynchronously
  840.  * between the two reads. The tick counter is examined before and after the
  841.  * hardware counter is read. If the tick counter changes, try again.
  842.  * Note: the hardware counter counts down from 65536.
  843.  */
  844. int32
  845. msclock (void)
  846. {
  847. int32 hi;
  848. uint lo;
  849. uint64 x;
  850.  
  851.     do {
  852.         hi = rdclock ();
  853.         lo = clockbits ();
  854.     } while (hi != rdclock ());
  855.  
  856.     x = ((uint64) (uint32) hi << 16) - lo;
  857.     return (int32) ((x * 11) / 13125);
  858. }
  859.  
  860.  
  861.  
  862. /* Return clock in seconds */
  863. int32
  864. secclock (void)
  865. {
  866. int32 hi;
  867. uint lo;
  868. uint64 x;
  869.  
  870.     do {
  871.         hi = rdclock ();
  872.         lo = clockbits ();
  873.     } while (hi != rdclock ());
  874.  
  875.     x = ((uint64) (uint32) hi << 16) - lo;
  876.     return (int32) ((x * 11) / 13125000);
  877. }
  878.  
  879.  
  880.  
  881. /* Directly read BIOS count of time ticks. This is used instead of
  882.  * calling biostime(0,0L). The latter calls BIOS INT 1A, AH=0,
  883.  * which resets the midnight overflow flag, losing days on the clock.
  884.  */
  885. static long
  886. bioscnt (void)
  887. {
  888. long rval;
  889. int i_state;
  890.  
  891.     i_state = disable ();
  892.     dosmemget (0x46c, sizeof (rval), &rval);
  893.     restore (i_state);
  894.     return rval;
  895. }
  896.  
  897.  
  898.  
  899. /* Atomic read-and-decrement operation.
  900.  * Read the variable pointed to by p. If it is
  901.  * non-zero, decrement it. Return the original value.
  902.  */
  903. int
  904. arddec (volatile int *p)
  905. {
  906. int tmp;
  907. int i_state;
  908.  
  909.     i_state = disable ();
  910.     tmp = *p;
  911.     if (tmp != 0)
  912.         (*p)--;
  913.     restore (i_state);
  914.     return tmp;
  915. }
  916.  
  917.  
  918.  
  919. void
  920. restore (int state)
  921. {
  922.     (void) (state ? enable (): disable ());
  923. }
  924.  
  925.  
  926.  
  927. int
  928. istate (void)
  929. {
  930. long flags;
  931.  
  932. #ifndef _lint
  933.     asm ( "pushfl\n\t"    /* We save the old ccr, which has interrupt mask bit. */
  934.           "popl %0\n\t":"=r" (flags));
  935. #else
  936.     flags = 0;
  937. #endif
  938.     return (flags >> 9) & 1;    /*lint !e704 */
  939. }
  940.  
  941. END_OF_FUNCTION(istate)
  942.  
  943.  
  944. /* This function is called by exit() in the GCC libc. We define
  945.  * it here to supersede the one defined in libc's stdio
  946.  */
  947. void
  948. _cleanup (void)
  949. {
  950.  
  951. }
  952.  
  953.  
  954.  
  955. /* clockbits - Read low order bits of timer 0 (the TOD clock)
  956.  * This works only for the 8254 chips used in ATs and 386s.
  957.  *
  958.  * The timer runs in mode 3 (square wave mode), counting down
  959.  * by twos, twice for each cycle. So it is necessary to read back the
  960.  * OUTPUT pin to see which half of the cycle we're in. I.e., the OUTPUT
  961.  * pin forms the most significant bit of the count. Unfortunately,
  962.  * the 8253 in the PC/XT lacks a command to read the OUTPUT pin...
  963.  *
  964.  * The PC's clock design is soooo brain damaged...
  965.  */
  966. static int16
  967. clockbits (void)
  968. {
  969. int i_state;
  970. unsigned int thestat, count;
  971.  
  972.     do {
  973.         i_state = disable ();
  974.         outportb (0x43, 0xc2);    /* latch timer 0 count and status for reading */
  975.         thestat = inportb (0x40);    /* get status of timer 0 */
  976.         count = inportb (0x40);    /* lsb of count */
  977.         count |= inportb (0x40) << 8;    /* msb of count */
  978.         restore (i_state);    /* no more chip references */
  979.     } while (thestat & 0x40);    /* reread if NULL COUNT bit set */
  980.  
  981.     thestat = (thestat & 0x80) << 8;    /* Shift OUTPUT to msb of 16-bit word */
  982.     count >>= 1;        /* count /= 2 */
  983.     if (count == 0)
  984.         return (int16) (thestat ^ 0x8000);    /* return complement of OUTPUT bit */
  985.     else
  986.         return (int16) (count | thestat);    /* Combine OUTPUT with counter */
  987. }
  988.  
  989.  
  990.  
  991. void
  992. kbint (void)
  993. {
  994.     ksignal (kbint, 1);
  995. }
  996.  
  997. END_OF_FUNCTION(kbint)
  998.  
  999.  
  1000.  
  1001. void
  1002. giveup (void)
  1003. {
  1004.     __dpmi_yield ();
  1005. }
  1006.  
  1007.  
  1008.  
  1009. void
  1010. sysreset (void)
  1011. {
  1012.     /* nothing! */
  1013. }
  1014.  
  1015.  
  1016.  
  1017. int16
  1018. lcsum (int16 * buf, int16 cnt)
  1019. {
  1020. uint32 sum = 0;
  1021.  
  1022.     while (cnt-- != 0)
  1023.         sum += *buf++;
  1024.     while (sum > 65535)
  1025.         sum = (sum & 0xffff) + (sum >> 16);
  1026.     return ((sum >> 8) | (sum << 8)) & 0xffff;
  1027. }
  1028.  
  1029.  
  1030.  
  1031. /* What a crock. All this inelegance should be replaced with something
  1032.  * that figures out what interrupt is being serviced by reading the 8259.
  1033.  */
  1034. #define IRQFN(n) static void irq##n (void) { eoi (); (*Int_tab[n].func) (Int_tab[n].arg);}
  1035.  
  1036. IRQFN(0)
  1037. IRQFN(1)
  1038. IRQFN(2)
  1039. IRQFN(3)
  1040. IRQFN(4)
  1041. IRQFN(5)
  1042. IRQFN(6)
  1043. IRQFN(7)
  1044. IRQFN(8)
  1045. IRQFN(9)
  1046. IRQFN(10)
  1047. IRQFN(11)
  1048. IRQFN(12)
  1049. IRQFN(13)
  1050. IRQFN(14)
  1051. IRQFN(15)
  1052.  
  1053. END_OF_FUNCTION(irq0)
  1054.  
  1055.  
  1056. static void (*Vectab[16]) (void) = {
  1057.     irq0, irq1, irq2, irq3, irq4, irq5, irq6, irq7, irq8, irq9, irq10, irq11,
  1058.     irq12, irq13, irq14, irq15
  1059. };
  1060.  
  1061.  
  1062.  
  1063. int
  1064. setvect (uint irq, int chain, void (*func) (int), int arg)
  1065. {
  1066. struct int_tab *ip;
  1067. uint intno;
  1068. int i;
  1069.  
  1070.     if (irq > 15)
  1071.         return -1;    /* IRQ out of legal range */
  1072.  
  1073.     ip = &Int_tab[irq];
  1074.     if (ip->func != NULL)
  1075.         return -1;    /* Already in use */
  1076.     /* Convert irq to actual CPU interrupt vector */
  1077.     intno = (irq < 8) ? irq + 8 : 0x70 + irq - 8;
  1078.  
  1079.     (void) __dpmi_get_protected_mode_interrupt_vector ((int) intno, &ip->old);
  1080.     ip->func = func;
  1081.     ip->arg = arg;
  1082.     ip->new.pm_offset = (unsigned long) Vectab[irq];
  1083.     ip->new.pm_selector = (int16) _go32_my_cs ();
  1084.     ip->chain = chain;
  1085.  
  1086.     if (chain)
  1087.         return _go32_dpmi_chain_protected_mode_interrupt_vector ((int) intno, &ip->new);
  1088.  
  1089.     if ((i = _go32_dpmi_allocate_iret_wrapper (&ip->new)) != 0)
  1090.         return i;
  1091.     return _go32_dpmi_set_protected_mode_interrupt_vector ((int) intno, &ip->new);
  1092. }
  1093.  
  1094.  
  1095.  
  1096. int
  1097. freevect (uint irq)
  1098. {
  1099. struct int_tab *ip;
  1100. int i;
  1101.  
  1102.     if (irq > 15)
  1103.         return -1;    /* IRQ out of legal range */
  1104.  
  1105.     ip = &Int_tab[irq];
  1106.     ip->func = NULL;
  1107.     /* Convert irq to actual CPU interrupt vector */
  1108.     irq = (irq < 8) ? irq + 8 : 0x70 + irq - 8;
  1109.     if (ip->chain)
  1110.         return _go32_dpmi_unchain_protected_mode_interrupt_vector (irq, &ip->new);
  1111.     if ((i = __dpmi_set_protected_mode_interrupt_vector ((int) irq, &ip->old)) != 0)
  1112.         return i;
  1113.     return _go32_dpmi_free_iret_wrapper (&ip->new);
  1114. }
  1115.  
  1116.  
  1117.  
  1118. /* Re-arm 8259 interrupt controller(s)
  1119.  * Should be called just after taking an interrupt, instead of just
  1120.  * before returning. This is because the 8259 inputs are edge triggered, and
  1121.  * new interrupts arriving during an interrupt service routine might be missed.
  1122.  */
  1123. static void
  1124. eoi (void)
  1125. {
  1126.     /* read in-service register from secondary 8259 */
  1127.     outportb (0xa0, 0x0b);
  1128.     if (inportb (0xa0))
  1129.         outportb (0xa0, 0x20);    /* Send EOI to secondary 8259 */
  1130.     outportb (0x20, 0x20);    /* Send EOI to primary 8259 */
  1131. }
  1132.  
  1133.  
  1134. END_OF_FUNCTION(eoi)
  1135.  
  1136.  
  1137. char Hashtab[256];
  1138.  
  1139.  
  1140.  
  1141. int16
  1142. hash_ip (uint32 ipaddr)
  1143. {
  1144. int h;
  1145.  
  1146.     h = ((ipaddr >> 16) & 0xFFFF) ^ (ipaddr & 0xFFFF);
  1147.     return (int16) uchar(Hashtab[((h >> 8) & 0xFF) ^ (h & 0xFF)]);    /*lint !e702 */
  1148. }
  1149.  
  1150.  
  1151.  
  1152. /* Convert a pointer to a long integer */
  1153. long
  1154. ptol (void *p)
  1155. {
  1156. long x;
  1157.  
  1158.     x = (long) FP_OFF (p);
  1159.     x |= (long) ((uint32) p << 16);    /*lint !e703 */
  1160.     return x;
  1161. }
  1162.  
  1163.  
  1164.  
  1165. void
  1166. strrev (char *str)
  1167. {
  1168. char *cp, *save, *cp2;
  1169.  
  1170.     save = mallocw (strlen (str) + 1);
  1171.     cp2 = str;
  1172.     cp = &save[strlen (str)];
  1173.     *cp-- = 0;
  1174.     while (*cp2)
  1175.         *cp-- = *cp2++;
  1176.     strcpy (str, save);
  1177.     free (save);
  1178. }
  1179.  
  1180.  
  1181.  
  1182. long
  1183. dostounix (struct date *dp, struct time *tp)
  1184. {
  1185. static struct tm tm;
  1186. struct tm *tx;
  1187. time_t now;
  1188.  
  1189.     tm.tm_year = dp->da_year - 1900;
  1190.     tm.tm_mon = dp->da_mon - 1;
  1191.     tm.tm_mday = dp->da_day;
  1192.     tm.tm_hour = tp->ti_hour;
  1193.     tm.tm_min = tp->ti_min;
  1194.     tm.tm_sec = tp->ti_sec;
  1195.     /* This desperately needs to be fixed.  How? */
  1196.     (void) time (&now);
  1197.     tx = localtime (&now);
  1198.     tm.tm_isdst = tx->tm_isdst;
  1199.     return (long) mktime (&tm);
  1200. }
  1201.  
  1202.  
  1203.  
  1204. static void
  1205. stowit (size_t theindex, int save, unsigned char attr)
  1206. {
  1207. char *nerf;
  1208. register int k, l, split;
  1209. register char *cp;
  1210.  
  1211.     nerf = (char *) mallocw(scrsize);
  1212.     if (save)    {
  1213.         ScreenRetrieve(nerf);
  1214.         if (DOSscreens[theindex].scrptr)
  1215.             free (DOSscreens[theindex].scrptr);
  1216.         DOSscreens[theindex].scrptr = nerf;
  1217.     } else    {
  1218.         memcpy (nerf, DOSscreens[theindex].scrptr, scrsize);
  1219.         if (attr & 0x80)    {
  1220.             attr &= 0x7f;
  1221.             l = (int) (scrsize / 2);
  1222.             split = Sessions[theindex].split;
  1223.             if (split)
  1224.                 l -= 160;    /* last 2 lines reversed */
  1225.             cp = (nerf + 1);
  1226.             for (k = 0; k < l; k++)    {
  1227.                 *cp &= 8;    /* keep high video bit */
  1228.                 *cp |= attr;
  1229.                 cp += 2;
  1230.                 }
  1231.             attr = ((attr & 0x0f) << 4) + ((attr & 0x70) >> 4);
  1232.             if (split)
  1233.                 for (k = 0; k < 160; k++)    {
  1234.                     *cp &= 8;    /* keep high video bit */
  1235.                     *cp |= attr;
  1236.                     cp += 2;
  1237.                 }
  1238.         }
  1239.         ScreenUpdate(nerf);
  1240.         free (nerf);
  1241.     }
  1242. }
  1243.  
  1244.  
  1245.  
  1246. void DOSinit ()
  1247. {
  1248. struct text_info tr;
  1249.  
  1250.     gettextinfo(&tr);
  1251.     orgMode = tr.currmode;
  1252.     if (vgaDesired)        {
  1253.         textmode ((int) C4350);
  1254.         gettextinfo(&tr);
  1255.     }
  1256.     SCREENwidth = tr.screenwidth;
  1257.     SCREENlength = tr.screenheight;
  1258.     window (1,1,SCREENwidth,SCREENlength);
  1259.     scrsize = 2 * tr.screenheight * tr.screenwidth;
  1260. }
  1261.  
  1262. void DOSterm ()
  1263. {
  1264. int k;
  1265.  
  1266.     for (k = 0; k < MAXSCR; k++)
  1267.         if (DOSscreens[k].scrptr)
  1268.             free (DOSscreens[k].scrptr);
  1269.     textmode (orgMode);
  1270. }
  1271.  
  1272.  
  1273. #undef free
  1274.  
  1275. /* Written to extend gopint.c in djgpp library */
  1276. static int
  1277. _go32_dpmi_unchain_protected_mode_interrupt_vector (uint irq, _go32_dpmi_seginfo * info)
  1278. {
  1279. __dpmi_paddr v;
  1280. char *stack;
  1281. char *wrapper;
  1282.  
  1283.     (void) __dpmi_get_protected_mode_interrupt_vector ((int) irq, &v);
  1284.     /* Sanity check: does the vector point into our program? A bug in gdb
  1285.      * keeps us from hooking the keyboard interrupt when we run under its
  1286.      * control. This test catches it.
  1287.      */
  1288.     if (v.selector != _go32_my_cs ())
  1289.         return -1;
  1290.     wrapper = (char *) v.offset32;
  1291.     /* Extract previous vector from the wrapper chainback area */
  1292.     v.offset32 = *(unsigned long *) (wrapper + 0x5b);
  1293.     v.selector = *(unsigned short *) (wrapper + 0x5f);
  1294.     /* Extract stack base from address of _call_count variable in wrapper */
  1295.     stack = (char *) (*(long *) (wrapper + 0x0F) - 8);
  1296. #define    STACK_WAS_MALLOCED    (1 << 0)
  1297.  
  1298.     if (*(long *) stack & STACK_WAS_MALLOCED)
  1299.         free (stack);
  1300.     free (wrapper);
  1301.     (void) __dpmi_set_protected_mode_interrupt_vector ((int) irq, &v);
  1302.     return 0;
  1303. }
  1304.  
  1305.  
  1306. #endif /* MSDOS */
  1307.